package com.flyqiu.common.spring;

import com.baomidou.mybatisplus.extension.service.IService;
import com.flyqiu.common.bean.FlyQiuBeanManage;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ClassUtils;

import java.util.Map;

/**
 * Spring Bean 管理类。
 * 提供了从 Spring 容器中获取 Bean 的功能，并支持动态注册 Bean。
 */
public class FlyQiuSpringProcBeanManage implements FlyQiuBeanManage {
    private final ApplicationContext applicationContext;
    private final AutowireCapableBeanFactory capableBeanFactory;

    /**
     * 构造函数。
     *
     * @param applicationContext 应用上下文
     * @param capableBeanFactory 自动装配工厂
     */
    public FlyQiuSpringProcBeanManage(ApplicationContext applicationContext, AutowireCapableBeanFactory capableBeanFactory) {
        this.applicationContext = applicationContext;
        this.capableBeanFactory = capableBeanFactory;
    }

    /**
     * 获取指定类型的 Bean。
     *
     * @param clazz Bean 类型
     * @param <T>   泛型类型
     * @return Bean 实例
     */
    @Override
    public <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 获取所有指定类型的 Bean 的映射。
     *
     * @param clazz Bean 类型
     * @param <T>   泛型类型
     * @return Bean 映射
     */
    @Override
    public <T> Map<String, T> getBeanMap(Class<T> clazz) {
        return applicationContext.getBeansOfType(clazz);
    }

    /**
     * 获取指定类型的 Mapper。
     *
     * @param clazz Mapper 类型
     * @param <T>   泛型类型
     * @return Mapper 实例
     */
    @Override
    public <T> T getMapper(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 自动装配 Bean。
     *
     * @param bean 待自动装配的 Bean
     */
    @Override
    public void autowire(Object bean) {
        capableBeanFactory.autowireBean(bean);
    }

    /**
     * 获取指定类型的服务。
     *
     * @param clazz 服务类型
     * @param <T>   泛型类型
     * @return 服务实例
     */
    @Override
    public <T extends IService<?>> T getService(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 向 Spring 容器中添加 Bean。
     *
     * @param clazz    Bean 类型
     * @param clazzInst Bean 实例
     * @param <T>      泛型类型
     */
    @Override
    public <T> void addBean(Class<T> clazz, T clazzInst) {
        addBeanToSpring(clazz, clazzInst);
    }

    /**
     * 向 Spring 容器中添加 Bean。
     *
     * @param clazzInst Bean 实例
     */
    @Override
    public void addBean(Object clazzInst) {
        addBeanToSpring(clazzInst);
    }

    /**
     * 检查 Spring 容器中是否存在指定类型的 Bean。
     *
     * @param clazz Bean 类型
     * @return 是否存在
     */
    @Override
    public boolean hasBean(Class<?> clazz) {
        try {
            Map<String, ?> beanMap = applicationContext.getBeansOfType(clazz);
            return !beanMap.isEmpty();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 向 Spring 容器中添加服务。
     *
     * @param clazz 服务类型
     * @param service 服务实例
     * @param <T>   泛型类型
     */
    @Override
    public <T extends IService<?>> void addService(Class<T> clazz, T service) {
        addBeanToSpring(clazz, service);
    }

    /**
     * 将 Bean 动态注册到 Spring 容器中。
     *
     * @param clazzInst Bean 实例
     * @param <T>       泛型类型
     */
    @SuppressWarnings("unchecked")
    private <T> void addBeanToSpring(T clazzInst) {
        Class<T> aClass = (Class<T>) clazzInst.getClass();
        addBeanToSpring(aClass, clazzInst);
    }

    /**
     * 将 Bean 动态注册到 Spring 容器中。
     *
     * @param clazz    Bean 类型
     * @param clazzInst Bean 实例
     * @param <T>      泛型类型
     */
    private <T> void addBeanToSpring(Class<T> clazz, T clazzInst) {
        // 将 application context 转换为 ConfigurableApplicationContext
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        // 获取 BeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory();
        String shortClassName = ClassUtils.getShortName(clazz);
        // 动态注册 Bean
        defaultListableBeanFactory.registerSingleton(shortClassName, clazzInst);
    }
}
